package com.github.tonydeng.fmj.pool;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.github.tonydeng.fmj.runner.ChiaCommandRunner;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;

@Component
public class ThreadPool implements InitializingBean {

    private static Logger logger = Logger.getLogger(ThreadPool.class);

    @Value("${plot.thread.pool.corePoolSize}")
    private int corePoolSize;

    @Value("${plot.thread.pool.keepAliveSeconds}")
    private int keepAliveSeconds;

    @Value("${plot.thread.pool.maxPoolSize}")
    private int maxPoolSize;

    @Value("${plot.thread.pool.queueCapacity}")
    private int queueCapacity;

    @Value("${plot.thread.pool.rejectedExecutionHandler}")
    private String rejectedExecutionHandler;

    @Value("${plot.thread.pool.listener.sleep.time}")
    private int sleepTime;

    private ThreadPoolTaskExecutor threadPool;

    @Autowired
    private ThreadPoolOps poolOps;

    @Autowired
    private ChiaCommandRunner chiaCommandRunner;

    @Autowired
    public RedisOpsUtil redisOpsUtil;

    public static ExecutorService cachedThreadPool2 = Executors.newCachedThreadPool();

    @Override
    public void afterPropertiesSet() throws Exception {
        threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(this.corePoolSize);
        threadPool.setKeepAliveSeconds(this.keepAliveSeconds);
        threadPool.setMaxPoolSize(this.maxPoolSize);
        threadPool.setQueueCapacity(this.queueCapacity);
        RejectedExecutionHandler handler = (RejectedExecutionHandler)
                Class.forName(rejectedExecutionHandler).newInstance();
        threadPool.setRejectedExecutionHandler(handler);
        threadPool.initialize();

        init();
    }

    public void init() {
        //程序启动1分钟内，调度任务不执行
        redisOpsUtil.setValue("startWork", "1", 60L);

        //重置使用的硬盘记录
        redisOpsUtil.delete("currentCount");

        //获取任务id
        List<Map<String, String>> workIdList = new ArrayList<>();
        Map<String, Map<String, String>> workList = poolOps.getWorkList();
        if (workList != null && !workList.isEmpty()) {
            workList.forEach((workId, values) -> {
                workIdList.add(values);
            });
        }

        cachedThreadPool2.execute(() -> {
            for (Map<String, String> map : workIdList
            ) {
                try {
                    String workId = map.get("workId");
                    String dCount = map.get("dCount");

                    //还在工作的进程不能删除
                    String working = redisOpsUtil.getValue("working_" + dCount + "_" + workId);
                    if(StrUtil.isNotEmpty(working)){
                        continue;
                    }

                    String tempDir = redisOpsUtil.getValue("tempDir_" + workId);
                    String temp2Dir = redisOpsUtil.getValue("temp2Dir_" + workId);

                    if (StrUtil.isNotEmpty(tempDir)) {
                        FileUtil.del(tempDir);
                    }

                    if (StrUtil.isNotEmpty(temp2Dir)) {
                        FileUtil.del(temp2Dir);
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
        });

        //清除所有记录的p盘记录
        poolOps.clearWorkList();

        ListenerRunnable listenerRunnable = new ListenerRunnable();
        Thread listenerThread = new Thread(listenerRunnable);
        listenerThread.setDaemon(true);
        listenerThread.start();
    }

    public void execute(Runnable task) {
        threadPool.execute(task);
    }

    class ListenerRunnable extends Observable implements Runnable {

        @Override
        public void run() {

            try {
                while (true) {
                    if (poolOps.waitListHasElements()) {
                        Map<String, String> values = poolOps.waitListOut();
                        threadPool.execute(new ThreadPoolTask(values, poolOps, chiaCommandRunner));
                    }
                    Thread.sleep(sleepTime);
                }
            } catch (Exception e) {
                logger.warn(e.getMessage());
            }
        }
    }
}
